package org.ru.mse10.cvis.service;

import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

import org.ru.mse10.cvis.dto.BaseDTO;
import org.ru.mse10.cvis.entity.misc.Identity;
import org.ru.mse10.cvis.entity.util.Bidirectional;
import org.ru.mse10.cvis.service.search.EntitySearcher;

/**
 * The Class EntityService.
 */
@Stateful
public class EntityService {

	/** The entity manager. */
	@PersistenceContext(type = PersistenceContextType.EXTENDED)
	private EntityManager entityManager;

	/**
	 * Gets the entity manager.
	 * 
	 * @return the entity manager
	 */
	protected EntityManager getEntityManager() {
		return entityManager;
	}

	/**
	 * Refresh.
	 * 
	 * @param <E>
	 *            the element type
	 * @param e
	 *            the e
	 */
	public <E> void refresh(E e) {
		getEntityManager().refresh(e);
	}

	/**
	 * Find.
	 * 
	 * @param <E>
	 *            the element type
	 * @param clazz
	 *            the clazz
	 * @param id
	 *            the id
	 * @return the e
	 */
	public <E> E find(Class<E> clazz, Long id) {
		return getEntityManager().find(clazz, id);
	}

	/**
	 * Save.
	 * 
	 * @param <E>
	 *            the element type
	 * @param e
	 *            the e
	 * @return the e
	 */
	public <E> E save(E e) {
		if (e instanceof Bidirectional) {
			((Bidirectional) e).initializeBidirectionalReferences();
		}
		return getEntityManager().merge(e);
	}

	/**
	 * Save in new tx.
	 * 
	 * @param <E>
	 *            the element type
	 * @param e
	 *            the e
	 * @return the e
	 */
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public <E> E saveInNewTx(E e) {
		return save(e);
	}

	/**
	 * Search.
	 * 
	 * @param <E>
	 *            the element type
	 * @param <D>
	 *            the generic type
	 * @param <S>
	 *            the generic type
	 * @param searcher
	 *            the searcher
	 * @param dto
	 *            the dto
	 * @param countOnly
	 *            the count only
	 */
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public <E extends Identity, D extends BaseDTO<E>, S extends EntitySearcher<E, D>> void search(
			S searcher, D dto, boolean countOnly) {
		searcher.search(getEntityManager(), dto, countOnly);
	}

	/**
	 * Creates the query.
	 * 
	 * @param queryString
	 *            the query string
	 * @return the query
	 */
	public Query createQuery(String queryString) {
		return getEntityManager().createQuery(queryString);
	}
}
